﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SpiceNet.Diagnostics;
using SpiceNet.Circuits;
using SpiceNet.Simulations;
using SpiceNet.Parameters;

namespace SpiceNet.Models
{
    /// <summary>
    /// A model used for a bipolar transistor
    /// </summary>
    public class BipolarModel : Model
    {
        /// <summary>
        /// Get parameters
        /// </summary>
        public override Dictionary<string, IP> ParamTable => _pTable;

        #region Parameters
        private enum _c
        {
            /* model parameters */
            BJT_MOD_NPN = 101,
            BJT_MOD_PNP = 102,
            BJT_MOD_IS = 103,
            BJT_MOD_BF = 104,
            BJT_MOD_NF = 105,
            BJT_MOD_VAF = 106,
            BJT_MOD_IKF = 107,
            BJT_MOD_ISE = 108,
            BJT_MOD_C2 = 109,
            BJT_MOD_NE = 110,
            BJT_MOD_BR = 111,
            BJT_MOD_NR = 112,
            BJT_MOD_VAR = 113,
            BJT_MOD_IKR = 114,
            BJT_MOD_ISC = 115,
            BJT_MOD_C4 = 116,
            BJT_MOD_NC = 117,
            BJT_MOD_RB = 118,
            BJT_MOD_IRB = 119,
            BJT_MOD_RBM = 120,
            BJT_MOD_RE = 121,
            BJT_MOD_RC = 122,
            BJT_MOD_CJE = 123,
            BJT_MOD_VJE = 124,
            BJT_MOD_MJE = 125,
            BJT_MOD_TF = 126,
            BJT_MOD_XTF = 127,
            BJT_MOD_VTF = 128,
            BJT_MOD_ITF = 129,
            BJT_MOD_PTF = 130,
            BJT_MOD_CJC = 131,
            BJT_MOD_VJC = 132,
            BJT_MOD_MJC = 133,
            BJT_MOD_XCJC = 134,
            BJT_MOD_TR = 135,
            BJT_MOD_CJS = 136,
            BJT_MOD_VJS = 137,
            BJT_MOD_MJS = 138,
            BJT_MOD_XTB = 139,
            BJT_MOD_EG = 140,
            BJT_MOD_XTI = 141,
            BJT_MOD_FC = 142,
            BJT_MOD_TNOM = 143,
            BJT_MOD_AF = 144,
            BJT_MOD_KF = 145,
            /* model questions */
            BJT_MOD_INVEARLYF = 301,
            BJT_MOD_INVEARLYR = 302,
            BJT_MOD_INVROLLOFFF = 303,
            BJT_MOD_INVROLLOFFR = 304,
            BJT_MOD_COLCONDUCT = 305,
            BJT_MOD_EMITTERCONDUCT = 306,
            BJT_MOD_TRANSVBCFACT = 307,
            BJT_MOD_EXCESSPHASEFACTOR = 308,
            BJT_MOD_TYPE = 309
        }
        private static Dictionary<string, IP> _pTable = new Dictionary<string, IP>
        {
            { "type", new IP(IF.OP, (int)_c.BJT_MOD_TYPE, T.STRING, "NPN or PNP") },
            { "npn", new IP(IF.IOPU, (int)_c.BJT_MOD_NPN, T.FLAG, "NPN type device") },
            { "pnp", new IP(IF.IOPU, (int)_c.BJT_MOD_PNP, T.FLAG, "PNP type device") },
            { "is", new IP(IF.IOP, (int)_c.BJT_MOD_IS, T.REAL, "Saturation Current") },
            { "bf", new IP(IF.IOP, (int)_c.BJT_MOD_BF, T.REAL, "Ideal forward beta") },
            { "nf", new IP(IF.IOP, (int)_c.BJT_MOD_NF, T.REAL, "Forward emission coefficient") },
            { "vaf", new IP(IF.IOP, (int)_c.BJT_MOD_VAF, T.REAL, "Forward Early voltage") },
            { "va", new IP(IF.IOPR, (int)_c.BJT_MOD_VAF, T.REAL, "Forward Early voltage") },
            { "ikf", new IP(IF.IOP, (int)_c.BJT_MOD_IKF, T.REAL, "Forward beta roll-off corner current") },
            { "ik", new IP(IF.IOPR, (int)_c.BJT_MOD_IKF, T.REAL, "Forward beta roll-off corner current") },
            { "ise", new IP(IF.IOP, (int)_c.BJT_MOD_ISE, T.REAL, "B-E leakage saturation current") },
             /*IOP("c2",   BJT_MOD_C2,   IF_REAL, "Obsolete parameter name"),*/
            { "ne", new IP(IF.IOP, (int)_c.BJT_MOD_NE, T.REAL, "B-E leakage emission coefficient") },
            { "br", new IP(IF.IOP, (int)_c.BJT_MOD_BR, T.REAL, "Ideal reverse beta") },
            { "nr", new IP(IF.IOP, (int)_c.BJT_MOD_NR, T.REAL, "Reverse emission coefficient") },
            { "var", new IP(IF.IOP, (int)_c.BJT_MOD_VAR, T.REAL, "Reverse Early voltage") },
            { "vb", new IP(IF.IOPR, (int)_c.BJT_MOD_VAR, T.REAL, "Reverse Early voltage") },
            { "ikr", new IP(IF.IOP, (int)_c.BJT_MOD_IKR, T.REAL, "reverse beta roll-off corner current") },
            { "isc", new IP(IF.IOP, (int)_c.BJT_MOD_ISC, T.REAL, "B-C leakage saturation current") },
             /*IOP("c4",   BJT_MOD_C4,   IF_REAL, "Obsolete parameter name"),*/
            { "nc", new IP(IF.IOP, (int)_c.BJT_MOD_NC, T.REAL, "B-C leakage emission coefficient") },
            { "rb", new IP(IF.IOP, (int)_c.BJT_MOD_RB, T.REAL, "Zero bias base resistance") },
            { "irb", new IP(IF.IOP, (int)_c.BJT_MOD_IRB, T.REAL, "Current for base resistance=(rb+rbm)/2") },
            { "rbm", new IP(IF.IOP, (int)_c.BJT_MOD_RBM, T.REAL, "Minimum base resistance") },
            { "re", new IP(IF.IOP, (int)_c.BJT_MOD_RE, T.REAL, "Emitter resistance") },
            { "rc", new IP(IF.IOP, (int)_c.BJT_MOD_RC, T.REAL, "Collector resistance") },
            { "cje", new IP(IF.IOPA, (int)_c.BJT_MOD_CJE, T.REAL, "Zero bias B-E depletion capacitance") },
            { "vje", new IP(IF.IOPA, (int)_c.BJT_MOD_VJE, T.REAL, "B-E built in potential") },
            { "pe", new IP(IF.IOPR, (int)_c.BJT_MOD_VJE, T.REAL, "B-E built in potential") },
            { "mje", new IP(IF.IOPA, (int)_c.BJT_MOD_MJE, T.REAL, "B-E junction grading coefficient") },
            { "me", new IP(IF.IOPR, (int)_c.BJT_MOD_MJE, T.REAL, "B-E junction grading coefficient") },
            { "tf", new IP(IF.IOPA, (int)_c.BJT_MOD_TF, T.REAL, "Ideal forward transit time") },
            { "xtf", new IP(IF.IOPA, (int)_c.BJT_MOD_XTF, T.REAL, "Coefficient for bias dependence of TF") },
            { "vtf", new IP(IF.IOPA, (int)_c.BJT_MOD_VTF, T.REAL, "Voltage giving VBC dependence of TF") },
            { "itf", new IP(IF.IOPA, (int)_c.BJT_MOD_ITF, T.REAL, "High current dependence of TF") },
            { "ptf", new IP(IF.IOPA, (int)_c.BJT_MOD_PTF, T.REAL, "Excess phase") },
            { "cjc", new IP(IF.IOPA, (int)_c.BJT_MOD_CJC, T.REAL, "Zero bias B-C depletion capacitance") },
            { "vjc", new IP(IF.IOPA, (int)_c.BJT_MOD_VJC, T.REAL, "B-C built in potential") },
            { "pc", new IP(IF.IOPR, (int)_c.BJT_MOD_VJC, T.REAL, "B-C built in potential") },
            { "mjc", new IP(IF.IOPA, (int)_c.BJT_MOD_MJC, T.REAL, "B-C junction grading coefficient") },
            { "mc", new IP(IF.IOPR, (int)_c.BJT_MOD_MJC, T.REAL, "B-C junction grading coefficient") },
            { "xcjc", new IP(IF.IOPA, (int)_c.BJT_MOD_XCJC, T.REAL, "Fraction of B-C cap to internal base") },
            { "tr", new IP(IF.IOPA, (int)_c.BJT_MOD_TR, T.REAL, "Ideal reverse transit time") },
            { "cjs", new IP(IF.IOPA, (int)_c.BJT_MOD_CJS, T.REAL, "Zero bias C-S capacitance") },
            { "ccs", new IP(IF.IOPA, (int)_c.BJT_MOD_CJS, T.REAL, "Zero bias C-S capacitance") },
            { "vjs", new IP(IF.IOPA, (int)_c.BJT_MOD_VJS, T.REAL, "Substrate junction built in potential") },
            { "ps", new IP(IF.IOPR, (int)_c.BJT_MOD_VJS, T.REAL, "Substrate junction built in potential") },
            { "mjs", new IP(IF.IOPA, (int)_c.BJT_MOD_MJS, T.REAL, "Substrate junction grading coefficient") },
            { "ms", new IP(IF.IOPR, (int)_c.BJT_MOD_MJS, T.REAL, "Substrate junction grading coefficient") },
            { "xtb", new IP(IF.IOP, (int)_c.BJT_MOD_XTB, T.REAL, "Forward and reverse beta temp. exp.") },
            { "eg", new IP(IF.IOP, (int)_c.BJT_MOD_EG, T.REAL, "Energy gap for IS temp. dependency") },
            { "xti", new IP(IF.IOP, (int)_c.BJT_MOD_XTI, T.REAL, "Temp. exponent for IS") },
            { "fc", new IP(IF.IOP, (int)_c.BJT_MOD_FC, T.REAL, "Forward bias junction fit parameter") },
            { "invearlyvoltf", new IP(IF.OPU, (int)_c.BJT_MOD_INVEARLYF, T.REAL, "Inverse early voltage:forward") },
            { "invearlyvoltr", new IP(IF.OPU, (int)_c.BJT_MOD_INVEARLYR, T.REAL, "Inverse early voltage:reverse") },
            { "invrollofff", new IP(IF.OPU, (int)_c.BJT_MOD_INVROLLOFFF, T.REAL, "Inverse roll off - forward") },
            { "invrolloffr", new IP(IF.OPU, (int)_c.BJT_MOD_INVROLLOFFR, T.REAL, "Inverse roll off - reverse") },
            { "collectorconduct", new IP(IF.OPU, (int)_c.BJT_MOD_COLCONDUCT, T.REAL, "Collector conductance") },
            { "emitterconduct", new IP(IF.OPU, (int)_c.BJT_MOD_EMITTERCONDUCT, T.REAL, "Emitter conductance") },
            { "transtimevbcfact", new IP(IF.OPU, (int)_c.BJT_MOD_TRANSVBCFACT, T.REAL, "Transit time VBC factor") },
            { "excessphasefactor", new IP(IF.OPU, (int)_c.BJT_MOD_EXCESSPHASEFACTOR, T.REAL, "Excess phase fact.") },
            { "tnom", new IP(IF.IOP, (int)_c.BJT_MOD_TNOM, T.REAL, "Parameter measurement temperature") },
            { "kf", new IP(IF.IOP, (int)_c.BJT_MOD_KF, T.REAL, "Flicker Noise Coefficient") },
            { "af", new IP(IF.IOP, (int)_c.BJT_MOD_AF, T.REAL, "Flicker Noise Exponent") }
        };

        /// <summary>
        /// Optional parameters
        /// </summary>
        public Parameter<int> BJTtype { get; } = new Parameter<int>(1);
        public Parameter<double> BJTsatCur { get; } = new Parameter<double>(1e-16);
        public Parameter<double> BJTbetaF { get; } = new Parameter<double>(100);
        public Parameter<double> BJTemissionCoeffF { get; } = new Parameter<double>(1);
        public Parameter<double> BJTleakBEemissionCoeff { get; } = new Parameter<double>(1.5);
        public Parameter<double> BJTbetaR { get; } = new Parameter<double>(1);
        public Parameter<double> BJTemissionCoeffR { get; } = new Parameter<double>(1);
        public Parameter<double> BJTleakBCemissionCoeff { get; } = new Parameter<double>(2);
        public Parameter<double> BJTbaseResist { get; } = new Parameter<double>(0);
        public Parameter<double> BJTemitterResist { get; } = new Parameter<double>(0);
        public Parameter<double> BJTcollectorResist { get; } = new Parameter<double>(0);
        public Parameter<double> BJTdepletionCapBE { get; } = new Parameter<double>(0);
        public Parameter<double> BJTpotentialBE { get; } = new Parameter<double>(.75);
        public Parameter<double> BJTjunctionExpBE { get; } = new Parameter<double>(.33);
        public Parameter<double> BJTtransitTimeF { get; } = new Parameter<double>(0);
        public Parameter<double> BJTtransitTimeBiasCoeffF { get; } = new Parameter<double>(0);
        public Parameter<double> BJTtransitTimeHighCurrentF { get; } = new Parameter<double>(0);
        public Parameter<double> BJTexcessPhase { get; } = new Parameter<double>(0);
        public Parameter<double> BJTdepletionCapBC { get; } = new Parameter<double>(0);
        public Parameter<double> BJTpotentialBC { get; } = new Parameter<double>(.75);
        public Parameter<double> BJTjunctionExpBC { get; } = new Parameter<double>(.33);
        public Parameter<double> BJTbaseFractionBCcap { get; } = new Parameter<double>(1);
        public Parameter<double> BJTtransitTimeR { get; } = new Parameter<double>(0);
        public Parameter<double> BJTcapCS { get; } = new Parameter<double>(0);
        public Parameter<double> BJTpotentialSubstrate { get; } = new Parameter<double>(.75);
        public Parameter<double> BJTexponentialSubstrate { get; } = new Parameter<double>(0);
        public Parameter<double> BJTbetaExp { get; } = new Parameter<double>(0);
        public Parameter<double> BJTenergyGap { get; } = new Parameter<double>(1.11);
        public Parameter<double> BJTtempExpIS { get; } = new Parameter<double>(3);
        public Parameter<double> BJTfNcoef { get; } = new Parameter<double>(0);
        public Parameter<double> BJTfNexp { get; } = new Parameter<double>(1);

        public Parameter<double> BJTrollOffR { get; } = new Parameter<double>();
        public Parameter<double> BJTearlyVoltR { get; } = new Parameter<double>();
        public Parameter<double> BJTtransitTimeFVBC { get; } = new Parameter<double>();
        public Parameter<double> BJTc4 { get; } = new Parameter<double>();
        public Parameter<double> BJTleakBCcurrent { get; } = new Parameter<double>();
        public Parameter<double> BJTc2 { get; } = new Parameter<double>();
        public Parameter<double> BJTtnom { get; } = new Parameter<double>();
        public Parameter<double> BJTrollOffF { get; } = new Parameter<double>();
        public Parameter<double> BJTearlyVoltF { get; } = new Parameter<double>();
        public Parameter<double> BJTminBaseResist { get; } = new Parameter<double>();
        public Parameter<double> BJTdepletionCapCoeff { get; } = new Parameter<double>();
        public Parameter<double> BJTleakBEcurrent { get; } = new Parameter<double>();
        public double BJTbaseCurrentHalfResist { get; private set; } = 0.0;
        #endregion

        #region Calculated constants
        /// <summary>
        /// Internally calculated constants
        /// </summary>
        public double BJTinvEarlyVoltF { get; private set; }    /* inverse of BJTearlyVoltF */
        public double BJTinvEarlyVoltR { get; private set; }    /* inverse of BJTearlyVoltR */
        public double BJTinvRollOffF { get; private set; }  /* inverse of BJTrollOffF */
        public double BJTinvRollOffR { get; private set; }  /* inverse of BJTrollOffR */
        public double BJTcollectorConduct { get; private set; } /* collector conductance */
        public double BJTemitterConduct { get; private set; }   /* emitter conductance */
        public double BJTtransitTimeVBCFactor { get; private set; } /* */
        public double BJTexcessPhaseFactor { get; private set; }
        public double BJTf2 { get; private set; }
        public double BJTf3 { get; private set; }
        public double BJTf6 { get; private set; }
        public double BJTf7 { get; private set; }
        #endregion

        #region Constants
        private const int NPN = 1;
        private const int PNP = -1;
        #endregion

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="name"></param>
        public BipolarModel(string name) : base(name) { }

        /// <summary>
        /// Set a parameter
        /// </summary>
        protected override void Param(int id, object value, Circuit ckt = null)
        {
            switch ((_c)id)
            {
                case _c.BJT_MOD_NPN:
                    BJTtype.Par(NPN);
                    break;
                case _c.BJT_MOD_PNP:
                    BJTtype.Par(PNP);
                    break;
                case _c.BJT_MOD_TNOM:
                    BJTtnom.Par((double)value + Circuit.CONSTCtoK);
                    break;
                case _c.BJT_MOD_IS:
                    BJTsatCur.Par((double)value);
                    break;
                case _c.BJT_MOD_BF:
                    BJTbetaF.Par((double)value);
                    break;
                case _c.BJT_MOD_NF:
                    BJTemissionCoeffF.Par((double)value);
                    break;
                case _c.BJT_MOD_VAF:
                    BJTearlyVoltF.Par((double)value);
                    break;
                case _c.BJT_MOD_IKF:
                    BJTrollOffF.Par((double)value);
                    break;
                case _c.BJT_MOD_ISE:
                    BJTleakBEcurrent.Par((double)value);
                    break;
                case _c.BJT_MOD_C2:
                    BJTc2.Par((double)value);
                    break;
                case _c.BJT_MOD_NE:
                    BJTleakBEemissionCoeff.Par((double)value);
                    break;
                case _c.BJT_MOD_BR:
                    BJTbetaR.Par((double)value);
                    break;
                case _c.BJT_MOD_NR:
                    BJTemissionCoeffR.Par((double)value);
                    break;
                case _c.BJT_MOD_VAR:
                    BJTearlyVoltR.Par((double)value);
                    break;
                case _c.BJT_MOD_IKR:
                    BJTrollOffR.Par((double)value);
                    break;
                case _c.BJT_MOD_ISC:
                    BJTleakBCcurrent.Par((double)value);
                    break;
                case _c.BJT_MOD_C4:
                    BJTc4.Par((double)value);
                    break;
                case _c.BJT_MOD_NC:
                    BJTleakBCemissionCoeff.Par((double)value);
                    break;
                case _c.BJT_MOD_RB:
                    BJTbaseResist.Par((double)value);
                    break;
                case _c.BJT_MOD_IRB:
                    BJTbaseCurrentHalfResist = (double)value;
                    break;
                case _c.BJT_MOD_RBM:
                    BJTminBaseResist.Par((double)value);
                    break;
                case _c.BJT_MOD_RE:
                    BJTemitterResist.Par((double)value);
                    break;
                case _c.BJT_MOD_RC:
                    BJTcollectorResist.Par((double)value);
                    break;
                case _c.BJT_MOD_CJE:
                    BJTdepletionCapBE.Par((double)value);
                    break;
                case _c.BJT_MOD_VJE:
                    BJTpotentialBE.Par((double)value);
                    break;
                case _c.BJT_MOD_MJE:
                    BJTjunctionExpBE.Par((double)value);
                    break;
                case _c.BJT_MOD_TF:
                    BJTtransitTimeF.Par((double)value);
                    break;
                case _c.BJT_MOD_XTF:
                    BJTtransitTimeBiasCoeffF.Par((double)value);
                    break;
                case _c.BJT_MOD_VTF:
                    BJTtransitTimeFVBC.Par((double)value);
                    break;
                case _c.BJT_MOD_ITF:
                    BJTtransitTimeHighCurrentF.Par((double)value);
                    break;
                case _c.BJT_MOD_PTF:
                    BJTexcessPhase.Par((double)value);
                    break;
                case _c.BJT_MOD_CJC:
                    BJTdepletionCapBC.Par((double)value);
                    break;
                case _c.BJT_MOD_VJC:
                    BJTpotentialBC.Par((double)value);
                    break;
                case _c.BJT_MOD_MJC:
                    BJTjunctionExpBC.Par((double)value);
                    break;
                case _c.BJT_MOD_XCJC:
                    BJTbaseFractionBCcap.Par((double)value);
                    break;
                case _c.BJT_MOD_TR:
                    BJTtransitTimeR.Par((double)value);
                    break;
                case _c.BJT_MOD_CJS:
                    BJTcapCS.Par((double)value);
                    break;
                case _c.BJT_MOD_VJS:
                    BJTpotentialSubstrate.Par((double)value);
                    break;
                case _c.BJT_MOD_MJS:
                    BJTexponentialSubstrate.Par((double)value);
                    break;
                case _c.BJT_MOD_XTB:
                    BJTbetaExp.Par((double)value);
                    break;
                case _c.BJT_MOD_EG:
                    BJTenergyGap.Par((double)value);
                    break;
                case _c.BJT_MOD_XTI:
                    BJTtempExpIS.Par((double)value);
                    break;
                case _c.BJT_MOD_FC:
                    BJTdepletionCapCoeff.Par((double)value);
                    break;
                case _c.BJT_MOD_KF:
                    BJTfNcoef.Par((double)value);
                    break;
                case _c.BJT_MOD_AF:
                    BJTfNexp.Par((double)value);
                    break;
                default:
                    throw new BadParameterException();
            }
        }

        /// <summary>
        /// Ask a parameter
        /// </summary>
        /// <param name="id"></param>
        /// <param name="ckt"></param>
        /// <returns></returns>
        protected override object Ask(int id, Circuit ckt = null)
        {
            switch ((_c)id)
            {
                case _c.BJT_MOD_TNOM:
                    return BJTtnom - Circuit.CONSTCtoK;
                case _c.BJT_MOD_IS:
                    return BJTsatCur.Value;
                case _c.BJT_MOD_BF:
                    return BJTbetaF.Value;
                case _c.BJT_MOD_NF:
                    return BJTemissionCoeffF.Value;
                case _c.BJT_MOD_VAF:
                    return BJTearlyVoltF.Value;
                case _c.BJT_MOD_IKF:
                    return BJTrollOffF.Value;
                case _c.BJT_MOD_ISE:
                    return BJTleakBEcurrent.Value;
                case _c.BJT_MOD_C2:
                    return BJTc2.Value;
                case _c.BJT_MOD_NE:
                    return BJTleakBEemissionCoeff.Value;
                case _c.BJT_MOD_BR:
                    return BJTbetaR.Value;
                case _c.BJT_MOD_NR:
                    return BJTemissionCoeffR.Value;
                case _c.BJT_MOD_VAR:
                    return BJTearlyVoltR.Value;
                case _c.BJT_MOD_IKR:
                    return BJTrollOffR.Value;
                case _c.BJT_MOD_ISC:
                    return BJTleakBCcurrent.Value;
                case _c.BJT_MOD_C4:
                    return BJTc4.Value;
                case _c.BJT_MOD_NC:
                    return BJTleakBCemissionCoeff.Value;
                case _c.BJT_MOD_RB:
                    return BJTbaseResist.Value;
                case _c.BJT_MOD_IRB:
                    return BJTbaseCurrentHalfResist;
                case _c.BJT_MOD_RBM:
                    return BJTminBaseResist.Value;
                case _c.BJT_MOD_RE:
                    return BJTemitterResist.Value;
                case _c.BJT_MOD_RC:
                    return BJTcollectorResist.Value;
                case _c.BJT_MOD_CJE:
                    return BJTdepletionCapBE.Value;
                case _c.BJT_MOD_VJE:
                    return BJTpotentialBE.Value;
                case _c.BJT_MOD_MJE:
                    return BJTjunctionExpBE.Value;
                case _c.BJT_MOD_TF:
                    return BJTtransitTimeF.Value;
                case _c.BJT_MOD_XTF:
                    return BJTtransitTimeBiasCoeffF.Value;
                case _c.BJT_MOD_VTF:
                    return BJTtransitTimeFVBC.Value;
                case _c.BJT_MOD_ITF:
                    return BJTtransitTimeHighCurrentF.Value;
                case _c.BJT_MOD_PTF:
                    return BJTexcessPhase.Value;
                case _c.BJT_MOD_CJC:
                    return BJTdepletionCapBC.Value;
                case _c.BJT_MOD_VJC:
                    return BJTpotentialBC.Value;
                case _c.BJT_MOD_MJC:
                    return BJTjunctionExpBC.Value;
                case _c.BJT_MOD_XCJC:
                    return BJTbaseFractionBCcap.Value;
                case _c.BJT_MOD_TR:
                    return BJTtransitTimeR.Value;
                case _c.BJT_MOD_CJS:
                    return BJTcapCS.Value;
                case _c.BJT_MOD_VJS:
                    return BJTpotentialSubstrate.Value;
                case _c.BJT_MOD_MJS:
                    return BJTexponentialSubstrate.Value;
                case _c.BJT_MOD_XTB:
                    return BJTbetaExp.Value;
                case _c.BJT_MOD_EG:
                    return BJTenergyGap.Value;
                case _c.BJT_MOD_XTI:
                    return BJTtempExpIS.Value;
                case _c.BJT_MOD_FC:
                    return BJTdepletionCapCoeff.Value;
                case _c.BJT_MOD_INVEARLYF:
                    return BJTinvEarlyVoltF;
                case _c.BJT_MOD_INVEARLYR:
                    return BJTinvEarlyVoltR;
                case _c.BJT_MOD_INVROLLOFFF:
                    return BJTinvRollOffF;
                case _c.BJT_MOD_INVROLLOFFR:
                    return BJTinvRollOffR;
                case _c.BJT_MOD_COLCONDUCT:
                    return BJTcollectorConduct;
                case _c.BJT_MOD_EMITTERCONDUCT:
                    return BJTemitterConduct;
                case _c.BJT_MOD_TRANSVBCFACT:
                    return BJTtransitTimeVBCFactor;
                case _c.BJT_MOD_EXCESSPHASEFACTOR:
                    return BJTexcessPhaseFactor;
                case _c.BJT_MOD_KF:
                    if (BJTfNcoef.Given)
                        return BJTfNcoef.Value;
                    else
                        return 0.0;
                case _c.BJT_MOD_AF:
                    if (BJTfNexp.Given)
                        return BJTfNexp.Value;
                    else
                        return 0.0;
                case _c.BJT_MOD_TYPE:
                    if (BJTtype == NPN)
                        return "npn";
                    else
                        return "pnp";
                default:
                    throw new BadParameterException();
            }
        }

        /// <summary>
        /// Parameters passed down for temperature-dependent calculations
        /// </summary>
        public class TempParams
        {
            public double xfc;
            public double fact1;
        }

        /// <summary>
        /// Do temperature-dependent calculations
        /// </summary>
        /// <param name="ckt"></param>
        public override void Temperature(Circuit ckt)
        {
            TempParams tp = new TempParams();
            if (!BJTtnom.Given) BJTtnom.Value = ckt.Config.NominalTemperature;
            tp.fact1 = BJTtnom / Circuit.CONSTRefTemp;

            if (!BJTleakBEcurrent.Given)
            {
                if (BJTc2.Given)
                {
                    BJTleakBEcurrent.Value = BJTc2 * BJTsatCur;
                }
                else
                {
                    BJTleakBEcurrent.Value = 0;
                }
            }
            if (!BJTleakBCcurrent.Given)
            {
                if (BJTc4.Given)
                {
                    BJTleakBCcurrent.Value = BJTc4 * BJTsatCur;
                }
                else
                {
                    BJTleakBCcurrent.Value = 0;
                }
            }
            if (!BJTminBaseResist.Given)
            {
                BJTminBaseResist.Value = BJTbaseResist;
            }

            /*
             * COMPATABILITY WARNING!
             * special note:  for backward compatability to much older models, spice 2G
             * implemented a special case which checked if B-E leakage saturation
             * current was >1, then it was instead a the B-E leakage saturation current
             * divided by IS, and multiplied it by IS at this point.  This was not
             * handled correctly in the 2G code, and there is some question on its 
             * reasonability, since it is also undocumented, so it has been left out
             * here.  It could easily be added with 1 line.  (The same applies to the B-C
             * leakage saturation current).   TQ  6/29/84
             */

            if (BJTearlyVoltF.Given && BJTearlyVoltF != 0)
            {
                BJTinvEarlyVoltF = 1 / BJTearlyVoltF;
            }
            else
            {
                BJTinvEarlyVoltF = 0;
            }
            if (BJTrollOffF.Given && BJTrollOffF != 0)
            {
                BJTinvRollOffF = 1 / BJTrollOffF;
            }
            else
            {
                BJTinvRollOffF = 0;
            }
            if (BJTearlyVoltR.Given && BJTearlyVoltR != 0)
            {
                BJTinvEarlyVoltR = 1 / BJTearlyVoltR;
            }
            else
            {
                BJTinvEarlyVoltR = 0;
            }
            if (BJTrollOffR.Given && BJTrollOffR != 0)
            {
                BJTinvRollOffR = 1 / BJTrollOffR;
            }
            else
            {
                BJTinvRollOffR = 0;
            }
            if (BJTcollectorResist.Given && BJTcollectorResist != 0)
            {
                BJTcollectorConduct = 1 / BJTcollectorResist;
            }
            else
            {
                BJTcollectorConduct = 0;
            }
            if (BJTemitterResist.Given && BJTemitterResist != 0)
            {
                BJTemitterConduct = 1 / BJTemitterResist;
            }
            else
            {
                BJTemitterConduct = 0;
            }
            if (BJTtransitTimeFVBC.Given && BJTtransitTimeFVBC != 0)
            {
                BJTtransitTimeVBCFactor = 1 / (BJTtransitTimeFVBC * 1.44);
            }
            else
            {
                BJTtransitTimeVBCFactor = 0;
            }
            BJTexcessPhaseFactor = (BJTexcessPhase /
                (180.0 / Circuit.CONSTPI)) * BJTtransitTimeF;
            if (BJTdepletionCapCoeff.Given)
            {
                if (BJTdepletionCapCoeff > .9999)
                {
                    BJTdepletionCapCoeff.Value = .9999;
                    CircuitWarning.Warning(this, string.Format("BJT model {0}, parameter fc limited to 0.9999", Name));
                }
            }
            else
            {
                BJTdepletionCapCoeff.Value = .5;
            }
            tp.xfc = Math.Log(1 - BJTdepletionCapCoeff);
            BJTf2 = Math.Exp((1 + BJTjunctionExpBE) * tp.xfc);
            BJTf3 = 1 - BJTdepletionCapCoeff *
                    (1 + BJTjunctionExpBE);
            BJTf6 = Math.Exp((1 + BJTjunctionExpBC) * tp.xfc);
            BJTf7 = 1 - BJTdepletionCapCoeff *
                    (1 + BJTjunctionExpBC);

            // Loop through all instances
            foreach (var inst in Instances)
                inst.Temperature(ckt, this, tp);
        }

        /// <summary>
        /// Bipolar transistors generate noise - override noiseless method
        /// </summary>
        /// <param name="ckt"></param>
        /// <param name="mode"></param>
        /// <param name="operation"></param>
        /// <param name="data"></param>
        /// <param name="outNdens"></param>
        public override void NoiseLoad(Circuit ckt, 
            Noise.OutputMode mode, 
            Noise.Operation operation, 
            NoiseData data, 
            ref double outNdens)
        {
            foreach (var inst in Instances)
                inst.NoiseLoad(ckt, mode, operation, data, ref outNdens, this);
        }
    }
}
